// 树型数据公共方法 tree = []
import {clone} from "./util"
// 遍历
const treeMap = (tree = [],fn = node => node,cfg = {}) => {  
  const isSource = cfg.isSource || false;
  const s = isSource?tree:clone(tree);
  const ck = cfg.children || 'children';
  // 节点遍历方法
  const f = (list,pn,ins) => {
      [...list].forEach((n,i) => {
          // 判断节点是否存在！
          if(n){
              fn(n,list,i,pn,ins); // 调用
              const c = n[ck]
              if(c && c.length > 0){
                  f(c,n,i)
              }
          }
      })
  }
  f(s,undefined,undefined)
  //
  return s;
}
// 过滤 fn()
const treeFilter = (tree = [],fn,cfg = {}) => {
  const ck = cfg.children || 'children';
  const f = (n,l,i,pn,ins) => {
      const bool = fn(n,l,i,pn,ins);
      if(!bool){
        const it = l.indexOf(n);
        l.splice(it,1)
        if(pn && pn[ck] && pn[ck].length == 0){
          delete pn[ck]
        }
      }
  }
  return treeMap(tree,f,cfg);
}
// 节点排序
const treeSort = (tree = [],fn,cfg = {}) => {
  const f = (n,l,i,pn,ins) => {
      l.sort(fn(n,l,i,pn,ins))
  }
  return treeMap(tree,f,cfg);
}
// 新增节点
const treeAdd = (tree = [],fn,cfg = {}) => {
  const ck = cfg.children || 'children';
  const f = (n,l,i,pn,ins) => {
      const ns = fn(pn) || []
      pn[ck] = [...pn[ck],...ns]
  }
  return treeMap(tree,f,cfg);
}
// 删除节点 依据节点 id 或者其他唯一值
const treeDelete = (tree = [],list = [],cfg = {}) => {
  const k = cfg.key || 'id';
  //
  const f = (n) => !list.includes(n[k])
  return treeFilter(tree,f,cfg)
}
// 生成一棵树上所有的路径 返回一个二维数组 [[目标节点,路径节点...]...] 路径节点集合不包含目标节点
const treeAllPath = (tree = [],cfg = {}) => {
  const paths = [];
  let s = [];
  //
  const f = (n,l,i,pn,ins) => {
    if(pn){
        const pi = s.indexOf(pn);
        const len = s.length;
        if(pi == -1){
            s.push(pn)
        }
        else if(pi < len - 1){
            let ct = len - 1 - pi;
            while(ct-- > 0){
                s.pop();
            }
        }
    }else{
        s = [];
    }
    paths.push([n,...s])
  }
  treeMap(tree,f,cfg);
  return paths;
}
// 叶节点和其路径提取 leaf 数据结构 [叶节点,父节点集合]
const treeLeafs = (tree = [],cfg = {}) => {
  // const leafs = [];
  const ck = cfg.children || 'children';
  // let s = [];
  // //
  // const f = (n,l,i,pn,ins) => {
  //     if(pn){
  //         const pi = s.indexOf(pn);
  //         const len = s.length;
  //         if(pi == -1){
  //             s.push(pn)
  //         }
  //         else if(pi < len - 1){
  //             let ct = len - 1 - pi;
  //             while(ct-- > 0){
  //                 s.pop();
  //             }
  //         }
  //     }else{
  //         s = [];
  //     }
  //     if(!n[ck] || n[ck].length == 0){
  //         leafs.push([n,...s])
  //     }
  // }
  // treeMap(tree,f,cfg);
  const paths = treeAllPath(tree,cfg)
  return paths.filter(items => !items[0][ck] || items[0][ck].length == 0)
}
// 查找节点，返回节点路径 list 是目标节点 id 集合 返回一个二维数组 [[目标节点,路径节点...]...]
const treeFindPath = (tree = [],list=[],cfg = {}) => {
  const k = cfg.key || 'id';
  const paths = treeAllPath(tree,cfg);
  return paths.filter(item => list.includes(item[0][k]))
}
// 重置树节点属性,包括 children 的名称都可以改，返回一颗新的树,保持该树的结构不变 并且当返回值为 undefined 时，删除该节点。。。
const treeReset = (tree = [],fn,cfg = {}) => {
  // menus 真实 children Name 
  const csk = cfg.sourceChildren || cfg.children || 'children';
  const ctk = cfg.children || 'children'
  const f = (n,l,i,pn,ins) => {
    const o = fn(n,l,i,pn,ins)
    if(!o){
      l.splice(i,1)
      return ;
    }
    const c = n[csk]
    const ks = Object.keys(n)
    ks.forEach(k => delete n[k]) // 清除原对象所有数据
    const oks = Object.keys(o)
    oks.forEach(k => n[k] = o[k]) // 重新设置原对象属性
    if(!o[ctk] && c && c.length > 0){
      n[ctk] = c; // 重新设定原对象 children 属性
    }
  }
  return treeMap(tree,f,cfg);
}
//
// 导出 树型数据处理方法，并将这些方法放入一个集合中
export {treeMap,treeFilter,treeSort,treeAdd,treeDelete,treeLeafs,treeAllPath,treeFindPath,treeReset}
